//------------------------------------------------------------------------------
// CCzoomr
//
// ProvidersHelper.cs
//
//------------------------------------------------------------------------------
// Copyright (c) 2007-2008, Scott Dorman (sj_dorman@hotmail.com)
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
// * Redistributions of source code must retain the above copyright notice, 
//   this list of conditions and the following disclaimer.
// 
// * Redistributions in binary form must reproduce the above copyright notice, 
//   this list of conditions and the following disclaimer in the documentation 
//   and/or other materials provided with the distribution.
// 
// * Neither the name of CCzoomr (http://www.CCzoomr.com) nor the names of its 
//   contributors may be used to endorse or promote products derived from this
//   software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. 
//------------------------------------------------------------------------------
using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Provider;
using System.Globalization;
using System.Threading;

namespace CCzoomr.Configuration.Provider
{
    /// <summary>
    /// Provides methods for creating provider instances, either singly or in a batch.
    /// <remarks>
    /// This is an adaptation of System.Web.Configuration.ProvidersHelper.
    /// </remarks>
    /// </summary>
    public static class ProvidersHelper
    {
        #region events
        #endregion

        #region class-wide fields
        private static Type providerBaseType = typeof(ProviderBase);
        #endregion

        #region private and internal properties and methods

        #region properties
        #endregion

        #region methods
        private static Type GetType(string typeName, bool ignoreCase)
        {
            Type type = null;
            try
            {
                if (TypeNameContainsAssembly(typeName))
                {
                    type = Type.GetType(typeName, true, ignoreCase);
                }
                if (type == null)
                {
                    type = Type.GetType(typeName, true, ignoreCase);
                }
            }
            catch (Exception exception)
            {
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                throw new ConfigurationErrorsException(exception.Message, exception);
            }
            return type;
        }

        internal static bool TypeNameContainsAssembly(string typeName)
        {
            return (CommaIndexInTypeName(typeName) > 0);
        }

        internal static int CommaIndexInTypeName(string typeName)
        {
            int num = typeName.LastIndexOf(',');
            if (num < 0)
            {
                return -1;
            }
            int num2 = typeName.LastIndexOf(']');
            if (num2 > num)
            {
                return -1;
            }
            return typeName.IndexOf(',', num2 + 1);
        }




        #endregion

        #endregion

        #region public properties and methods

        #region properties
        #endregion

        #region methods

        /// <summary>
        /// Instantiates the provider.
        /// </summary>
        /// <param name="pSettings">The settings.</param>
        /// <param name="pType">Type of the provider to be instantiated.</param>
        /// <returns></returns>
        public static ProviderBase InstantiateProvider(ProviderSettings providerSettings, Type providerType)
        {
            if (providerSettings == null)
            {
                throw new ArgumentNullException(Properties.Resources.ArgumentNull_Obj, "providerSettings");
            }

            ProviderBase providerBase = null;

            try
            {
                string typeName = (providerSettings.Type == null) ? null : providerSettings.Type.Trim();
                if (string.IsNullOrEmpty(typeName))
                {
                    throw new ArgumentException(Properties.Resources.Provider_No_Type_Name);
                }
                Type c = GetType(typeName, true);
                    //GetType(providerType.FullName, true, true);

                if (!providerType.IsAssignableFrom(c))
                {
                    throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Properties.Resources.Config_Provider_Must_Implement_Type, providerType.FullName));
                }

                providerBase = Activator.CreateInstance(c) as ProviderBase;
                NameValueCollection parameters = providerSettings.Parameters;
                NameValueCollection config = new NameValueCollection(parameters.Count, StringComparer.Ordinal);
                foreach (string text in parameters)
                {
                    config[text] = parameters[text];
                }

                providerBase.Initialize(providerSettings.Name, config);

            }
            catch (Exception ex)
            {
                if (ex is ConfigurationException)
                {
                    throw;
                }

                throw new ConfigurationErrorsException(ex.Message, providerSettings.ElementInformation.Properties["type"].Source, providerSettings.ElementInformation.Properties["type"].LineNumber);
            }

            return providerBase;
        }

        /// <summary>
        /// Instantiates the providers.
        /// </summary>
        /// <param name="pProviderSettings">The provider settings.</param>
        /// <param name="pProviders">The providers to be populated.</param>
        /// <param name="pType">Type of the provider to be instantiated.</param>
        public static void InstantiateProviders(ProviderSettingsCollection configProviders, ProviderCollection providers, Type providerType)
        {
            if (configProviders == null)
            {
                throw new ArgumentNullException(Properties.Resources.ArgumentNull_Obj, "configProviders");
            }
            if (providers == null)
            {
                throw new ArgumentNullException(Properties.Resources.ArgumentNull_Obj, "providers");
            }
            if (providerType == null)
            {
                throw new ArgumentNullException(Properties.Resources.ArgumentNull_Obj, "providerType");
            }

            foreach (ProviderSettings settings in configProviders)
            {
                providers.Add(ProvidersHelper.InstantiateProvider(settings, providerType));
            }
        }
        #endregion

        #endregion
    }
}
